home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / nsHelperAppDlg.js < prev    next >
Text File  |  2007-10-18  |  40KB  |  1,009 lines

  1. /*
  2. //@line 42 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  3. */
  4.  
  5. /* This file implements the nsIHelperAppLauncherDialog interface.
  6.  *
  7.  * The implementation consists of a JavaScript "class" named nsUnknownContentTypeDialog,
  8.  * comprised of:
  9.  *   - a JS constructor function
  10.  *   - a prototype providing all the interface methods and implementation stuff
  11.  *
  12.  * In addition, this file implements an nsIModule object that registers the
  13.  * nsUnknownContentTypeDialog component.
  14.  */
  15.  
  16.  
  17. /* ctor
  18.  */
  19. function nsUnknownContentTypeDialog() {
  20.     // Initialize data properties.
  21.     this.mLauncher = null;
  22.     this.mContext  = null;
  23.     this.mSourcePath = null;
  24.     this.chosenApp = null;
  25.     this.givenDefaultApp = false;
  26.     this.updateSelf = true;
  27.     this.mTitle    = "";
  28. }
  29.  
  30. nsUnknownContentTypeDialog.prototype = {
  31.     nsIMIMEInfo  : Components.interfaces.nsIMIMEInfo,
  32.  
  33.     // This "class" supports nsIHelperAppLauncherDialog, and nsISupports.
  34.     QueryInterface: function (iid) {
  35.         if (!iid.equals(Components.interfaces.nsIHelperAppLauncherDialog) &&
  36.             !iid.equals(Components.interfaces.nsISupports)) {
  37.             throw Components.results.NS_ERROR_NO_INTERFACE;
  38.         }
  39.         return this;
  40.     },
  41.  
  42.     // ---------- nsIHelperAppLauncherDialog methods ----------
  43.  
  44.     // show: Open XUL dialog using window watcher.  Since the dialog is not
  45.     //       modal, it needs to be a top level window and the way to open
  46.     //       one of those is via that route).
  47.     show: function(aLauncher, aContext, aReason)  {
  48.       this.mLauncher = aLauncher;
  49.       this.mContext  = aContext;
  50.  
  51.       const nsITimer = Components.interfaces.nsITimer;
  52.       this._timer = Components.classes["@mozilla.org/timer;1"]
  53.                               .createInstance(nsITimer);
  54.       this._timer.initWithCallback(this, 0, nsITimer.TYPE_ONE_SHOT);
  55.     },
  56.  
  57.     // When opening from new tab, if tab closes while dialog is opening,
  58.     // (which is a race condition on the XUL file being cached and the timer
  59.     // in nsExternalHelperAppService), the dialog gets a blur and doesn't
  60.     // activate the OK button.  So we wait a bit before doing opening it.
  61.     reallyShow: function() {
  62.         var ir = this.mContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor);
  63.         var dwi = ir.getInterface(Components.interfaces.nsIDOMWindowInternal);
  64.         var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  65.                            .getService(Components.interfaces.nsIWindowWatcher);
  66.         this.mDialog = ww.openWindow(dwi,
  67.                                      "chrome://mozapps/content/downloads/unknownContentType.xul",
  68.                                      null,
  69.                                      "chrome,centerscreen,titlebar,dialog=yes,dependent",
  70.                                      null);
  71.  
  72.         // Hook this object to the dialog.
  73.         this.mDialog.dialog = this;
  74.  
  75.         // Hook up utility functions.
  76.         this.getSpecialFolderKey = this.mDialog.getSpecialFolderKey;
  77.  
  78.         // Watch for error notifications.
  79.         this.progressListener.helperAppDlg = this;
  80.         this.mLauncher.setWebProgressListener(this.progressListener);
  81.     },
  82.  
  83.     // promptForSaveToFile:  Display file picker dialog and return selected file.
  84.     //                       This is called by the External Helper App Service
  85.     //                       after the ucth dialog calls |saveToDisk| with a null
  86.     //                       target filename (no target, therefore user must pick).
  87.     //
  88.     //                       Alternatively, if the user has selected to have all
  89.     //                       files download to a specific location, return that
  90.     //                       location and don't ask via the dialog. 
  91.     //
  92.     // Note - this function is called without a dialog, so it cannot access any part
  93.     // of the dialog XUL as other functions on this object do. 
  94.     promptForSaveToFile: function(aLauncher, aContext, aDefaultFile, aSuggestedFileExtension) {
  95.       var result = "";
  96.       
  97.       this.mLauncher = aLauncher;
  98.  
  99.       // If the user is always downloading to the same location, the default download
  100.       // folder is stored in preferences. If a value is found stored, use that 
  101.       // automatically and don't ask via a dialog. 
  102.       var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  103.       var autodownload = prefs.getBoolPref("browser.download.useDownloadDir");
  104.       if (autodownload) {
  105.         function getSpecialFolderKey(aFolderType) 
  106.         {
  107.           if (aFolderType == "Desktop")
  108.             return "Desk";
  109.         
  110.           if (aFolderType != "Downloads")
  111.             throw "ASSERTION FAILED: folder type should be 'Desktop' or 'Downloads'";
  112.         
  113. //@line 153 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  114.           return "Pers";
  115. //@line 161 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  116.         }
  117.         
  118.         function getDownloadsFolder(aFolder)
  119.         {
  120.           var fileLocator = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties);
  121.  
  122.           var dir = fileLocator.get(getSpecialFolderKey(aFolder), Components.interfaces.nsILocalFile);
  123.           
  124.           var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
  125.           bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
  126.  
  127.           var description = bundle.GetStringFromName("myDownloads");
  128.           if (aFolder != "Desktop")
  129.             dir.append(description);
  130.             
  131.           return dir;
  132.         }
  133.  
  134.         var defaultFolder = null;
  135.         switch (prefs.getIntPref("browser.download.folderList")) {
  136.         case 0:
  137.           defaultFolder = getDownloadsFolder("Desktop");
  138.           break;
  139.         case 1:
  140.           defaultFolder = getDownloadsFolder("Downloads");
  141.           break;
  142.         case 2:
  143.           defaultFolder = prefs.getComplexValue("browser.download.dir", Components.interfaces.nsILocalFile);
  144.           break;
  145.         }
  146.         
  147.         result = this.validateLeafName(defaultFolder, aDefaultFile, aSuggestedFileExtension);
  148.       }
  149.       
  150.       if (!result) {
  151.         // Use file picker to show dialog.
  152.         var nsIFilePicker = Components.interfaces.nsIFilePicker;
  153.         var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  154.  
  155.         var bundle = Components.classes["@mozilla.org/intl/stringbundle;1"].getService(Components.interfaces.nsIStringBundleService);
  156.         bundle = bundle.createBundle("chrome://mozapps/locale/downloads/unknownContentType.properties");
  157.  
  158.         var windowTitle = bundle.GetStringFromName("saveDialogTitle");
  159.         var parent = aContext.QueryInterface(Components.interfaces.nsIInterfaceRequestor).getInterface(Components.interfaces.nsIDOMWindowInternal);
  160.         picker.init(parent, windowTitle, nsIFilePicker.modeSave);
  161.         picker.defaultString = aDefaultFile;
  162.  
  163.         if (aSuggestedFileExtension) {
  164.           // aSuggestedFileExtension includes the period, so strip it
  165.           picker.defaultExtension = aSuggestedFileExtension.substring(1);
  166.         } 
  167.         else {
  168.           try {
  169.             picker.defaultExtension = this.mLauncher.MIMEInfo.primaryExtension;
  170.           } 
  171.           catch (ex) { }
  172.         }
  173.  
  174.         var wildCardExtension = "*";
  175.         if (aSuggestedFileExtension) {
  176.           wildCardExtension += aSuggestedFileExtension;
  177.           picker.appendFilter(this.mLauncher.MIMEInfo.description, wildCardExtension);
  178.         }
  179.  
  180.         picker.appendFilters( nsIFilePicker.filterAll );
  181.  
  182.         // Pull in the user's preferences and get the default download directory.
  183.         var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  184.         try {
  185.           var startDir = prefs.getComplexValue("browser.download.dir", Components.interfaces.nsILocalFile);
  186.           if (startDir.exists()) {
  187.             picker.displayDirectory = startDir;
  188.           }
  189.         } 
  190.         catch(exception) { }
  191.  
  192.         var dlgResult = picker.show();
  193.  
  194.         if (dlgResult == nsIFilePicker.returnCancel) {
  195.           // null result means user cancelled.
  196.           return null;
  197.         }
  198.  
  199.  
  200.         // Be sure to save the directory the user chose through the Save As... 
  201.         // dialog  as the new browser.download.dir
  202.         result = picker.file;
  203.  
  204.         if (result) {
  205.           try {
  206.             // Remove the file so that it's not there when we ensure non-existence later;
  207.             // this is safe because for the file to exist, the user would have had to
  208.             // confirm that he wanted the file overwritten.
  209.             if (result.exists())
  210.               result.remove(false);
  211.           }
  212.           catch (e) { }
  213.           var newDir = result.parent;
  214.           prefs.setComplexValue("browser.download.dir", Components.interfaces.nsILocalFile, newDir);
  215.           result = this.validateLeafName(newDir, result.leafName, null);
  216.         }
  217.       }
  218.       return result;
  219.     },
  220.  
  221.     /**
  222.      * Ensures that a local folder/file combination does not already exist in
  223.      * the file system (or finds such a combination with a reasonably similar
  224.      * leaf name), creates the corresponding file, and returns it.
  225.      *
  226.      * @param   aLocalFile
  227.      *          the folder where the file resides
  228.      * @param   aLeafName
  229.      *          the string name of the file (may be empty if no name is known,
  230.      *          in which case a name will be chosen)
  231.      * @param   aFileExt
  232.      *          the extension of the file, if one is known; this will be ignored
  233.      *          if aLeafName is non-empty
  234.      * @returns nsILocalFile
  235.      *          the created file
  236.      */
  237.     validateLeafName: function (aLocalFile, aLeafName, aFileExt)
  238.     {
  239.       if (!aLocalFile || !aLocalFile.exists())
  240.         return null;
  241.  
  242.       // Remove any leading periods, since we don't want to save hidden files
  243.       // automatically.
  244.       aLeafName = aLeafName.replace(/^\.+/, "");
  245.  
  246.       if (aLeafName == "")
  247.         aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
  248.       aLocalFile.append(aLeafName);
  249.  
  250.       this.makeFileUnique(aLocalFile);
  251.  
  252.       if (aLocalFile.isExecutable() && !this.mLauncher.targetFile.isExecutable()) {
  253.         var f = aLocalFile.clone();
  254.         aLocalFile.leafName = aLocalFile.leafName + "." + this.mLauncher.MIMEInfo.primaryExtension; 
  255.  
  256.         f.remove(false);
  257.         this.makeFileUnique(aLocalFile);
  258.       }
  259.  
  260.       return aLocalFile;
  261.     },
  262.  
  263.     /**
  264.      * Generates and returns a uniquely-named file from aLocalFile.  If
  265.      * aLocalFile does not exist, it will be the file returned; otherwise, a
  266.      * file whose name is similar to that of aLocalFile will be returned.
  267.      */
  268.     makeFileUnique: function (aLocalFile)
  269.     {
  270.       try {
  271.         // Note - this code is identical to that in 
  272.         //   toolkit/content/contentAreaUtils.js.
  273.         // If you are updating this code, update that code too! We can't share code
  274.         // here since this is called in a js component. 
  275.         var collisionCount = 0;
  276.         while (aLocalFile.exists()) {
  277.           collisionCount++;
  278.           if (collisionCount == 1) {
  279.             // Append "(2)" before the last dot in (or at the end of) the filename
  280.             // special case .ext.gz etc files so we don't wind up with .tar(2).gz
  281.             if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i)) {
  282.               aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&");
  283.             }
  284.             else {
  285.               aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
  286.             }
  287.           }
  288.           else {
  289.             // replace the last (n) in the filename with (n+1)
  290.             aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
  291.           }
  292.         }
  293.         aLocalFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
  294.       }
  295.       catch (e) {
  296.         dump("*** exception in validateLeafName: " + e + "\n");
  297.         if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
  298.           aLocalFile.append("unnamed");
  299.           if (aLocalFile.exists())
  300.             aLocalFile.createUnique(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0600);
  301.         }
  302.       }
  303.     },
  304.     
  305.     // ---------- implementation methods ----------
  306.  
  307.     // Web progress listener so we can detect errors while mLauncher is
  308.     // streaming the data to a temporary file.
  309.     progressListener: {
  310.         // Implementation properties.
  311.         helperAppDlg: null,
  312.  
  313.         // nsIWebProgressListener methods.
  314.         // Look for error notifications and display alert to user.
  315.         onStatusChange: function( aWebProgress, aRequest, aStatus, aMessage ) {
  316.             if ( aStatus != Components.results.NS_OK ) {
  317.                 // Get prompt service.
  318.                 var prompter = Components.classes[ "@mozilla.org/embedcomp/prompt-service;1" ]
  319.                                    .getService( Components.interfaces.nsIPromptService );
  320.                 // Display error alert (using text supplied by back-end).
  321.                 prompter.alert( this.dialog, this.helperAppDlg.mTitle, aMessage );
  322.  
  323.                 // Close the dialog.
  324.                 this.helperAppDlg.onCancel();
  325.                 if ( this.helperAppDlg.mDialog ) {
  326.                     this.helperAppDlg.mDialog.close();
  327.                 }
  328.             }
  329.         },
  330.  
  331.         // Ignore onProgressChange, onStateChange, onLocationChange, and onSecurityChange notifications.
  332.         onProgressChange: function( aWebProgress,
  333.                                     aRequest,
  334.                                     aCurSelfProgress,
  335.                                     aMaxSelfProgress,
  336.                                     aCurTotalProgress,
  337.                                     aMaxTotalProgress ) {
  338.         },
  339.  
  340.         onProgressChange64: function( aWebProgress,
  341.                                       aRequest,
  342.                                       aCurSelfProgress,
  343.                                       aMaxSelfProgress,
  344.                                       aCurTotalProgress,
  345.                                       aMaxTotalProgress ) {
  346.         },
  347.  
  348.  
  349.  
  350.         onStateChange: function( aWebProgress, aRequest, aStateFlags, aStatus ) {
  351.         },
  352.  
  353.         onLocationChange: function( aWebProgress, aRequest, aLocation ) {
  354.         },
  355.  
  356.         onSecurityChange: function( aWebProgress, aRequest, state ) {
  357.         }
  358.     },
  359.  
  360.     // initDialog:  Fill various dialog fields with initial content.
  361.     initDialog : function() {
  362.       // Put file name in window title.
  363.       var suggestedFileName = this.mLauncher.suggestedFileName;
  364.  
  365.       // Some URIs do not implement nsIURL, so we can't just QI.
  366.       var url   = this.mLauncher.source;
  367.       var fname = "";
  368.       this.mSourcePath = url.prePath;
  369.       try {
  370.           url = url.QueryInterface( Components.interfaces.nsIURL );
  371.           // A url, use file name from it.
  372.           fname = url.fileName;
  373.           this.mSourcePath += url.directory;
  374.       } catch (ex) {
  375.           // A generic uri, use path.
  376.           fname = url.path;
  377.           this.mSourcePath += url.path;
  378.       }
  379.  
  380.       if (suggestedFileName)
  381.         fname = suggestedFileName;
  382.       
  383.       var displayName = fname.replace(/ +/g, " ");
  384.  
  385.       this.mTitle = this.dialogElement("strings").getFormattedString("title", [displayName]);
  386.       this.mDialog.document.title = this.mTitle;
  387.  
  388.       // Put content type, filename and location into intro.
  389.       this.initIntro(url, fname, displayName);
  390.  
  391.       var iconString = "moz-icon://" + fname + "?size=16&contentType=" + this.mLauncher.MIMEInfo.MIMEType;
  392.       this.dialogElement("contentTypeImage").setAttribute("src", iconString);
  393.  
  394.       // if always-save and is-executable and no-handler
  395.       // then set up simple ui
  396.       var mimeType = this.mLauncher.MIMEInfo.MIMEType;
  397.       var shouldntRememberChoice = (mimeType == "application/octet-stream" || 
  398.                                     mimeType == "application/x-msdownload" ||
  399.                                     this.mLauncher.targetFile.isExecutable());
  400.       if (shouldntRememberChoice && !this.openWithDefaultOK()) {
  401.         // hide featured choice 
  402.         this.mDialog.document.getElementById("normalBox").collapsed = true;
  403.         // show basic choice 
  404.         this.mDialog.document.getElementById("basicBox").collapsed = false;
  405.         // change button labels
  406.         this.mDialog.document.documentElement.getButton("accept").label = this.dialogElement("strings").getString("unknownAccept.label");
  407.         this.mDialog.document.documentElement.getButton("cancel").label = this.dialogElement("strings").getString("unknownCancel.label");
  408.         // hide other handler
  409.         this.mDialog.document.getElementById("openHandler").collapsed = true;
  410.         // set save as the selected option
  411.         this.dialogElement("mode").selectedItem = this.dialogElement("save");
  412.       }
  413.       else {
  414.         this.initAppAndSaveToDiskValues();
  415.  
  416.         // Initialize "always ask me" box. This should always be disabled
  417.         // and set to true for the ambiguous type application/octet-stream.
  418.         // We don't also check for application/x-msdownload here since we
  419.         // want users to be able to autodownload .exe files. 
  420.         var rememberChoice = this.dialogElement("rememberChoice");
  421.  
  422. //@line 487 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  423.         if (shouldntRememberChoice) {
  424.           rememberChoice.checked = false;
  425.           rememberChoice.disabled = true;
  426.         }
  427.         else {
  428.           rememberChoice.checked = !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
  429.         }
  430.         this.toggleRememberChoice(rememberChoice);
  431.  
  432.         // XXXben - menulist won't init properly, hack. 
  433.         var openHandler = this.dialogElement("openHandler");
  434.         openHandler.parentNode.removeChild(openHandler);
  435.         var openHandlerBox = this.dialogElement("openHandlerBox");
  436.         openHandlerBox.appendChild(openHandler);
  437.       }
  438.  
  439.       this.mDialog.setTimeout("dialog.postShowCallback()", 0);
  440.       
  441.       this.mDialog.document.documentElement.getButton("accept").disabled = true;
  442.       const nsITimer = Components.interfaces.nsITimer;
  443.       this._timer = Components.classes["@mozilla.org/timer;1"]
  444.                               .createInstance(nsITimer);
  445.       this._timer.initWithCallback(this, 250, nsITimer.TYPE_ONE_SHOT);
  446.     },
  447.  
  448.     _timer: null,
  449.     notify: function (aTimer) {
  450.       if (!this.mDialog) {
  451.         this.reallyShow();
  452.       } else {
  453.         // The user may have already cancelled the dialog.
  454.         try {
  455.           if (!this._blurred) {
  456.             this.mDialog.document.documentElement.getButton("accept").disabled = false;
  457.           }
  458.         } catch (ex) {}
  459.         this._delayExpired = true;
  460.       }
  461.       // The timer won't release us, so we have to release it.
  462.       this._timer = null;
  463.     },
  464.  
  465.     postShowCallback: function () {
  466.       this.mDialog.sizeToContent();
  467.  
  468.       // Set initial focus
  469.       this.dialogElement("mode").focus();
  470.     },
  471.  
  472.     // initIntro:
  473.     initIntro: function(url, filename, displayname) {
  474.         this.dialogElement( "location" ).value = displayname;
  475.         this.dialogElement( "location" ).setAttribute("realname", filename);
  476.         this.dialogElement( "location" ).setAttribute("tooltiptext", displayname);
  477.  
  478.         // if mSourcePath is a local file, then let's use the pretty path name instead of an ugly
  479.         // url...
  480.         var pathString = this.mSourcePath;
  481.         try 
  482.         {
  483.           var fileURL = url.QueryInterface(Components.interfaces.nsIFileURL);
  484.           if (fileURL)
  485.           {
  486.             var fileObject = fileURL.file;
  487.             if (fileObject)
  488.             {
  489.               var parentObject = fileObject.parent;
  490.               if (parentObject)
  491.               {
  492.                 pathString = parentObject.path;
  493.               }
  494.             }
  495.           }
  496.         } catch(ex) {}
  497.  
  498.         if (pathString == this.mSourcePath)
  499.         {
  500.           // wasn't a fileURL
  501.           var tmpurl = url.clone(); // don't want to change the real url
  502.           try {
  503.             tmpurl.userPass = "";
  504.           } catch (ex) {}
  505.           pathString = tmpurl.prePath;
  506.         }
  507.  
  508.         // Set the location text, which is separate from the intro text so it can be cropped
  509.         var location = this.dialogElement( "source" );
  510.         location.value = pathString;
  511.         location.setAttribute("tooltiptext", this.mSourcePath);
  512.         
  513.         // Show the type of file. 
  514.         var type = this.dialogElement("type");
  515.         var mimeInfo = this.mLauncher.MIMEInfo;
  516.         
  517.         // 1. Try to use the pretty description of the type, if one is available.
  518.         var typeString = mimeInfo.description;
  519.         
  520.         if (typeString == "") {
  521.           // 2. If there is none, use the extension to identify the file, e.g. "ZIP file"
  522.           var primaryExtension = "";
  523.           try {
  524.             primaryExtension = mimeInfo.primaryExtension;
  525.           }
  526.           catch (ex) {
  527.           }
  528.           if (primaryExtension != "")
  529.             typeString = primaryExtension.toUpperCase() + " file";
  530.           // 3. If we can't even do that, just give up and show the MIME type. 
  531.           else
  532.             typeString = mimeInfo.MIMEType;
  533.         }
  534.         
  535.         type.value = typeString;
  536.     },
  537.     
  538.     _blurred: false,
  539.     _delayExpired: false, 
  540.     onBlur: function(aEvent) {
  541.       if (aEvent.target != this.mDialog.document)
  542.         return;
  543.       this._blurred = true;
  544.       this.mDialog.document.documentElement.getButton("accept").disabled = true;
  545.     },
  546.     
  547.     onFocus: function(aEvent) {
  548.       if (aEvent.target != this.mDialog.document)
  549.         return;
  550.       this._blurred = false;
  551.       if (this._delayExpired) {
  552.         var script = "document.documentElement.getButton('accept').disabled = false";
  553.         this.mDialog.setTimeout(script, 250);
  554.       }
  555.     },
  556.  
  557.     // Returns true if opening the default application makes sense.
  558.     openWithDefaultOK: function() {
  559.         var result;
  560.  
  561.         // The checking is different on Windows...
  562. //@line 627 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  563.         // Windows presents some special cases.
  564.         // We need to prevent use of "system default" when the file is
  565.         // executable (so the user doesn't launch nasty programs downloaded
  566.         // from the web), and, enable use of "system default" if it isn't
  567.         // executable (because we will prompt the user for the default app
  568.         // in that case).
  569.         
  570.         // Need to get temporary file and check for executable-ness.
  571.         var tmpFile = this.mLauncher.targetFile;
  572.         
  573.         //  Default is Ok if the file isn't executable (and vice-versa).
  574.         return !tmpFile.isExecutable();
  575. //@line 645 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  576.     },
  577.     
  578.     // Set "default" application description field.
  579.     initDefaultApp: function() {
  580.       // Use description, if we can get one.
  581.       var desc = this.mLauncher.MIMEInfo.defaultDescription;
  582.       if (desc) {
  583.         var defaultApp = this.dialogElement("strings").getFormattedString("defaultApp", [desc]);
  584.         this.dialogElement("defaultHandler").label = defaultApp;
  585.       }
  586.       else {
  587.         this.dialogElement("modeDeck").setAttribute("selectedIndex", "1");
  588.         // Hide the default handler item too, in case the user picks a 
  589.         // custom handler at a later date which triggers the menulist to show.
  590.         this.dialogElement("defaultHandler").hidden = true;
  591.       }
  592.     },
  593.  
  594.     // getPath:
  595.     getPath: function (aFile) {
  596. //@line 668 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  597.       return aFile.path;
  598. //@line 670 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  599.     },
  600.  
  601.     // initAppAndSaveToDiskValues:
  602.     initAppAndSaveToDiskValues: function() {
  603.       var modeGroup = this.dialogElement("mode");
  604.  
  605.       // We don't let users open .exe files or random binary data directly 
  606.       // from the browser at the moment because of security concerns. 
  607.       var openWithDefaultOK = this.openWithDefaultOK();
  608.       var mimeType = this.mLauncher.MIMEInfo.MIMEType;
  609.       if (this.mLauncher.targetFile.isExecutable() || (
  610.           (mimeType == "application/octet-stream" ||
  611.            mimeType == "application/x-msdownload") && 
  612.            !openWithDefaultOK)) {
  613.         this.dialogElement("open").disabled = true;
  614.         var openHandler = this.dialogElement("openHandler");
  615.         openHandler.disabled = true;
  616.         openHandler.selectedItem = null;
  617.         modeGroup.selectedItem = this.dialogElement("save");
  618.         return;
  619.       }
  620.     
  621.       // Fill in helper app info, if there is any.
  622.       this.chosenApp = this.mLauncher.MIMEInfo.preferredApplicationHandler;
  623.       // Initialize "default application" field.
  624.       this.initDefaultApp();
  625.  
  626.       var otherHandler = this.dialogElement("otherHandler");
  627.               
  628.       // Fill application name textbox.
  629.       if (this.chosenApp && this.chosenApp.path) {
  630.         otherHandler.setAttribute("path", this.getPath(this.chosenApp));
  631.         otherHandler.label = this.chosenApp.leafName;
  632.         otherHandler.hidden = false;
  633.       }
  634.  
  635.       var useDefault = this.dialogElement("useSystemDefault");
  636.       var openHandler = this.dialogElement("openHandler");
  637.       openHandler.selectedIndex = 0;
  638.  
  639.       if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useSystemDefault) {
  640.         // Open (using system default).
  641.         modeGroup.selectedItem = this.dialogElement("open");
  642.       } else if (this.mLauncher.MIMEInfo.preferredAction == this.nsIMIMEInfo.useHelperApp) {
  643.         // Open with given helper app.
  644.         modeGroup.selectedItem = this.dialogElement("open");
  645.         openHandler.selectedIndex = 1;
  646.       } else {
  647.         // Save to disk.
  648.         modeGroup.selectedItem = this.dialogElement("save");
  649.       }
  650.       
  651.       // If we don't have a "default app" then disable that choice.
  652.       if (!openWithDefaultOK) {
  653.         var useDefault = this.dialogElement("defaultHandler");
  654.         var isSelected = useDefault.selected;
  655.         
  656.         // Disable that choice.
  657.         useDefault.hidden = true;
  658.         // If that's the default, then switch to "save to disk."
  659.         if (isSelected) {
  660.           openHandler.selectedIndex = 1;
  661.           modeGroup.selectedItem = this.dialogElement("save");
  662.         }
  663.       }
  664.       
  665.       // otherHandler is always disabled on Mac
  666. //@line 741 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  667.       otherHandler.nextSibling.hidden = otherHandler.nextSibling.nextSibling.hidden = false;
  668. //@line 743 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  669.       this.updateOKButton();
  670.     },
  671.  
  672.     // Returns the user-selected application
  673.     helperAppChoice: function() {
  674.       return this.chosenApp;
  675.     },
  676.     
  677.     get saveToDisk() {
  678.       return this.dialogElement("save").selected;
  679.     },
  680.     
  681.     get useOtherHandler() {
  682.       return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 1;
  683.     },
  684.     
  685.     get useSystemDefault() {
  686.       return this.dialogElement("open").selected && this.dialogElement("openHandler").selectedIndex == 0;
  687.     },
  688.     
  689.     toggleRememberChoice: function (aCheckbox) {
  690.         this.dialogElement("settingsChange").hidden = !aCheckbox.checked;
  691.         this.mDialog.sizeToContent();
  692.     },
  693.     
  694.     openHandlerCommand: function () {
  695.       var openHandler = this.dialogElement("openHandler");
  696.       if (openHandler.selectedItem.id == "choose")
  697.         this.chooseApp();
  698.       else
  699.         openHandler.setAttribute("lastSelectedItemID", openHandler.selectedItem.id);
  700.     },
  701.  
  702.     updateOKButton: function() {
  703.       var ok = false;
  704.       if (this.dialogElement("save").selected) {
  705.         // This is always OK.
  706.         ok = true;
  707.       } 
  708.       else if (this.dialogElement("open").selected) {
  709.         switch (this.dialogElement("openHandler").selectedIndex) {
  710.         case 0:
  711.           // No app need be specified in this case.
  712.           ok = true;
  713.           break;
  714.         case 1:
  715.           // only enable the OK button if we have a default app to use or if 
  716.           // the user chose an app....
  717.           ok = this.chosenApp || /\S/.test(this.dialogElement("otherHandler").getAttribute("path")); 
  718.         break;
  719.         }
  720.       }
  721.  
  722.       // Enable Ok button if ok to press.
  723.       this.mDialog.document.documentElement.getButton("accept").disabled = !ok;
  724.     },
  725.     
  726.     // Returns true iff the user-specified helper app has been modified.
  727.     appChanged: function() {
  728.       return this.helperAppChoice() != this.mLauncher.MIMEInfo.preferredApplicationHandler;
  729.     },
  730.  
  731.     updateMIMEInfo: function() {
  732.       var needUpdate = false;
  733.       // If current selection differs from what's in the mime info object,
  734.       // then we need to update.
  735.       if (this.saveToDisk) {
  736.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.saveToDisk;
  737.         if (needUpdate)
  738.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.saveToDisk;
  739.       } 
  740.       else if (this.useSystemDefault) {
  741.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useSystemDefault;
  742.         if (needUpdate)
  743.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useSystemDefault;
  744.       } 
  745.       else {
  746.         // For "open with", we need to check both preferred action and whether the user chose
  747.         // a new app.
  748.         needUpdate = this.mLauncher.MIMEInfo.preferredAction != this.nsIMIMEInfo.useHelperApp || this.appChanged();
  749.         if (needUpdate) {
  750.           this.mLauncher.MIMEInfo.preferredAction = this.nsIMIMEInfo.useHelperApp;
  751.           // App may have changed - Update application and description
  752.           var app = this.helperAppChoice();
  753.           this.mLauncher.MIMEInfo.preferredApplicationHandler = app;
  754.           this.mLauncher.MIMEInfo.applicationDescription = "";
  755.         }
  756.       }
  757.       // We will also need to update if the "always ask" flag has changed.
  758.       needUpdate = needUpdate || this.mLauncher.MIMEInfo.alwaysAskBeforeHandling != (!this.dialogElement("rememberChoice").checked);
  759.  
  760.       // One last special case: If the input "always ask" flag was false, then we always
  761.       // update.  In that case we are displaying the helper app dialog for the first
  762.       // time for this mime type and we need to store the user's action in the mimeTypes.rdf
  763.       // data source (whether that action has changed or not; if it didn't change, then we need
  764.       // to store the "always ask" flag so the helper app dialog will or won't display
  765.       // next time, per the user's selection).
  766.       needUpdate = needUpdate || !this.mLauncher.MIMEInfo.alwaysAskBeforeHandling;
  767.  
  768.       // Make sure mime info has updated setting for the "always ask" flag.
  769.       this.mLauncher.MIMEInfo.alwaysAskBeforeHandling = !this.dialogElement("rememberChoice").checked;
  770.  
  771.       return needUpdate;        
  772.     },
  773.     
  774.     // See if the user changed things, and if so, update the
  775.     // mimeTypes.rdf entry for this mime type.
  776.     updateHelperAppPref: function() {
  777.       var ha = new this.mDialog.HelperApps();
  778.       ha.updateTypeInfo(this.mLauncher.MIMEInfo);
  779.       ha.destroy();
  780.     },
  781.     
  782.     // onOK:
  783.     onOK: function() {
  784.       // Verify typed app path, if necessary.
  785.       if (this.useOtherHandler) {
  786.         var helperApp = this.helperAppChoice();
  787.         if (!helperApp || !helperApp.exists()) {
  788.           // Show alert and try again.        
  789.           var bundle = this.dialogElement("strings");                    
  790.           var msg = bundle.getFormattedString("badApp", [this.dialogElement("otherHandler").path]);
  791.           var svc = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  792.           svc.alert(this.mDialog, bundle.getString("badApp.title"), msg);
  793.  
  794.           // Disable the OK button.
  795.           this.mDialog.document.documentElement.getButton("accept").disabled = true;
  796.           this.dialogElement("mode").focus();          
  797.  
  798.           // Clear chosen application.
  799.           this.chosenApp = null;
  800.  
  801.           // Leave dialog up.
  802.           return false;
  803.         }
  804.       }
  805.         
  806.       // Remove our web progress listener (a progress dialog will be
  807.       // taking over).
  808.       this.mLauncher.setWebProgressListener(null);
  809.       
  810.       // saveToDisk and launchWithApplication can return errors in 
  811.       // certain circumstances (e.g. The user clicks cancel in the
  812.       // "Save to Disk" dialog. In those cases, we don't want to
  813.       // update the helper application preferences in the RDF file.
  814.       try {
  815.         var needUpdate = this.updateMIMEInfo();
  816.         
  817.         if (this.dialogElement("save").selected) {
  818.           // If we're using a default download location, create a path
  819.           // for the file to be saved to to pass to |saveToDisk| - otherwise
  820.           // we must ask the user to pick a save name.
  821.  
  822. //@line 910 "/cygdrive/K/tinderbuild/src/flock/mozilla/toolkit/mozapps/downloads/src/nsHelperAppDlg.js.in"
  823.           this.mLauncher.saveToDisk(null, false);
  824.         }
  825.         else
  826.           this.mLauncher.launchWithApplication(null, false);
  827.  
  828.         // Update user pref for this mime type (if necessary). We do not
  829.         // store anything in the mime type preferences for the ambiguous
  830.         // type application/octet-stream. We do NOT do this for 
  831.         // application/x-msdownload since we want users to be able to 
  832.         // autodownload these to disk. 
  833.         if (needUpdate && this.mLauncher.MIMEInfo.MIMEType != "application/octet-stream")
  834.           this.updateHelperAppPref();
  835.       } catch(e) { }
  836.  
  837.       // Unhook dialog from this object.
  838.       this.mDialog.dialog = null;
  839.  
  840.       // Close up dialog by returning true.
  841.       return true;
  842.     },
  843.  
  844.     // onCancel:
  845.     onCancel: function() {
  846.       // Remove our web progress listener.
  847.       this.mLauncher.setWebProgressListener(null);
  848.  
  849.       // Cancel app launcher.
  850.       try {
  851.         const NS_BINDING_ABORTED = 0x804b0002;
  852.         this.mLauncher.cancel(NS_BINDING_ABORTED);
  853.       } catch(exception) {
  854.       }
  855.  
  856.       // Unhook dialog from this object.
  857.       this.mDialog.dialog = null;
  858.  
  859.       // Close up dialog by returning true.
  860.       return true;
  861.     },
  862.  
  863.     // dialogElement:  Convenience. 
  864.     dialogElement: function(id) {
  865.       return this.mDialog.document.getElementById(id);
  866.     },
  867.  
  868.     // chooseApp:  Open file picker and prompt user for application.
  869.     chooseApp: function() {
  870.       var nsIFilePicker = Components.interfaces.nsIFilePicker;
  871.       var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
  872.       fp.init(this.mDialog,
  873.               this.dialogElement("strings").getString("chooseAppFilePickerTitle"),
  874.               nsIFilePicker.modeOpen);
  875.  
  876.       fp.appendFilters(nsIFilePicker.filterApps);
  877.  
  878.       if (fp.show() == nsIFilePicker.returnOK && fp.file) {
  879.         // Show the "handler" menulist since we have a (user-specified) 
  880.         // application now.
  881.         this.dialogElement("modeDeck").setAttribute("selectedIndex", "0");
  882.         
  883.         // Remember the file they chose to run.
  884.         this.chosenApp = fp.file;
  885.         // Update dialog.
  886.         var otherHandler = this.dialogElement("otherHandler");
  887.         otherHandler.removeAttribute("hidden");
  888.         otherHandler.setAttribute("path", this.getPath(this.chosenApp));
  889.         otherHandler.label = this.chosenApp.leafName;
  890.         this.dialogElement("openHandler").selectedIndex = 1;
  891.         this.dialogElement("openHandler").setAttribute("lastSelectedItemID", "otherHandler");
  892.         
  893.         this.dialogElement("mode").selectedItem = this.dialogElement("open");
  894.       }
  895.       else {
  896.         var openHandler = this.dialogElement("openHandler");
  897.         var lastSelectedID = openHandler.getAttribute("lastSelectedItemID");
  898.         if (!lastSelectedID)
  899.           lastSelectedID = "defaultHandler";
  900.         openHandler.selectedItem = this.dialogElement(lastSelectedID);
  901.       }
  902.     },
  903.  
  904.     // Turn this on to get debugging messages.
  905.     debug: false,
  906.  
  907.     // Dump text (if debug is on).
  908.     dump: function( text ) {
  909.         if ( this.debug ) {
  910.             dump( text ); 
  911.         }
  912.     },
  913.  
  914.     // dumpInfo:
  915.     doDebug: function() {
  916.         const nsIProgressDialog = Components.interfaces.nsIProgressDialog;
  917.         // Open new progress dialog.
  918.         var progress = Components.classes[ "@mozilla.org/progressdialog;1" ]
  919.                          .createInstance( nsIProgressDialog );
  920.         // Show it.
  921.         progress.open( this.mDialog );
  922.     },
  923.  
  924.     // dumpObj:
  925.     dumpObj: function( spec ) {
  926.          var val = "<undefined>";
  927.          try {
  928.              val = eval( "this."+spec ).toString();
  929.          } catch( exception ) {
  930.          }
  931.          this.dump( spec + "=" + val + "\n" );
  932.     },
  933.  
  934.     // dumpObjectProperties
  935.     dumpObjectProperties: function( desc, obj ) {
  936.          for( prop in obj ) {
  937.              this.dump( desc + "." + prop + "=" );
  938.              var val = "<undefined>";
  939.              try {
  940.                  val = obj[ prop ];
  941.              } catch ( exception ) {
  942.              }
  943.              this.dump( val + "\n" );
  944.          }
  945.     }
  946. }
  947.  
  948. // This Component's module implementation.  All the code below is used to get this
  949. // component registered and accessible via XPCOM.
  950. var module = {
  951.     firstTime: true,
  952.  
  953.     // registerSelf: Register this component.
  954.     registerSelf: function (compMgr, fileSpec, location, type) {
  955.         if (this.firstTime) {
  956.             this.firstTime = false;
  957.             throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  958.         }
  959.         compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  960.  
  961.         compMgr.registerFactoryLocation( this.cid,
  962.                                          "Unknown Content Type Dialog",
  963.                                          this.contractId,
  964.                                          fileSpec,
  965.                                          location,
  966.                                          type );
  967.     },
  968.  
  969.     // getClassObject: Return this component's factory object.
  970.     getClassObject: function (compMgr, cid, iid) {
  971.         if (!cid.equals(this.cid)) {
  972.             throw Components.results.NS_ERROR_NO_INTERFACE;
  973.         }
  974.  
  975.         if (!iid.equals(Components.interfaces.nsIFactory)) {
  976.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  977.         }
  978.  
  979.         return this.factory;
  980.     },
  981.  
  982.     /* CID for this class */
  983.     cid: Components.ID("{F68578EB-6EC2-4169-AE19-8C6243F0ABE1}"),
  984.  
  985.     /* Contract ID for this class */
  986.     contractId: "@mozilla.org/helperapplauncherdialog;1",
  987.  
  988.     /* factory object */
  989.     factory: {
  990.         // createInstance: Return a new nsProgressDialog object.
  991.         createInstance: function (outer, iid) {
  992.             if (outer != null)
  993.                 throw Components.results.NS_ERROR_NO_AGGREGATION;
  994.  
  995.             return (new nsUnknownContentTypeDialog()).QueryInterface(iid);
  996.         }
  997.     },
  998.  
  999.     // canUnload: n/a (returns true)
  1000.     canUnload: function(compMgr) {
  1001.         return true;
  1002.     }
  1003. };
  1004.  
  1005. // NSGetModule: Return the nsIModule object.
  1006. function NSGetModule(compMgr, fileSpec) {
  1007.     return module;
  1008. }
  1009.